#ifndef __DEBUG_H__
#define __DEBUG_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdarg.h>

/** @brief For target, disable log by default
 *	If  compile switch is set for a compilation unit
 *	messages will be totally disabled by default
 */
#if !defined(__linux) && !defined(_WIN32) && !defined(ARDUINO)
	#define AC_TRACE_DISABLE	1
#endif

#define AC_TRACE_ENABLE
#define TRACE_LEVEL			DEBUG

/** @brief Allow to force enabling messaging using AC_TRACE_ENABLE define  */
#ifdef AC_TRACE_ENABLE
	#undef AC_TRACE_DISABLE
#endif


/** @brief Helper macro for calling ac_trace()
 *	If AC_TRACE_DISABLE compile switch is set for a compilation unit
 *	messages will be totally disabled
 */
#define AC_TRACE(level, ...) 	      _AC_TRACE(level, __VA_ARGS__)

/** @brief Helper macro for calling ac_trace_setup()
 *	If AC_TRACE_DISABLE compile switch is set for a compilation unit
 *	messages will be totally disabled
 */
#define AC_TRACE_SETUP(level, printer) _AC_TRACE_SETUP(level, printer)

/** @brief Helper macro for calling ac_trace_setup_level()
 *	If AC_TRACE_DISABLE compile switch is set for a compilation unit
 *	messages will be totally disabled
 */
#define AC_TRACE_SETUP_LEVEL(level) 	  _AC_TRACE_SETUP_LEVEL(level)

/** @brief Helper macro for calling ac_trace_setup_default()
 *	If AC_TRACE_DISABLE compile switch is set for a compilation unit
 *	messages will be totally disabled
 */
#define AC_TRACE_SETUP_DEFAULT()       _AC_TRACE_SETUP_DEFAULT()

/** @brief Return current level
 *	@warning This macro may expand as a function call
 */
#define AC_TRACE_LEVEL                 _AC_TRACE_LEVEL

#if defined(AC_TRACE_DISABLE)
	#define _AC_TRACE(level, ...)           (void)0
	#define _AC_TRACE_SETUP(level, printer) (void)0
	#define _AC_TRACE_SETUP_LEVEL(level)    (void)0
	#define _AC_TRACE_LEVEL                 OFF
#else
	#define _AC_TRACE(level, ...)           ac_trace(level, __VA_ARGS__)
 	#define _AC_TRACE_SETUP(level, printer) ac_trace_setup(level, printer)
 	#define _AC_TRACE_SETUP_LEVEL(level)    ac_trace_setup(level, ac_trace_printer_default)
	#define _AC_TRACE_SETUP_DEFAULT()       ac_trace_setup_default()
	#define _AC_TRACE_LEVEL                 ac_trace_get_level()
#endif

/** @brief message level definition
 */
enum ac_trace_level {
	OFF     = 0,
	ERROR,
	WARNING,
	INFO,
	VERBOSE,
	DEBUG,
	MAX
};


/** @brief Prototype for print routine function
 */
typedef void (*ac_trace_printer_t)(int level, const char * str, va_list ap);


/** @brief Set message level and printer function
 *  @param[in] level   only message above level will be passed to printer function
 *  @param[in] printer user provided function in charge printing message
 *  @return none
 */
void ac_trace_setup(int level, ac_trace_printer_t printer);


/** @brief Default printer function that display messages to stderr
 *  Function uses stdio. Care must be taken on embeded platfrom.
 *  Function does nothing with IAR compiler.
 *  @return none
 */
void ac_trace_printer_default(int level, const char * str, va_list ap);

/** @brief Set message level
 *  Default printer function will be used.
 *  @param[in] level   only message above level will be passed to printer function
 *  @return none
 */
static inline void ac_trace_setup_level(int level)
{
	ac_trace_setup(level, ac_trace_printer_default);
}


/** @brief Set default message level and printer
 *  @return none
 */
static inline void ac_trace_setup_default(void)
{
	ac_trace_setup(INFO, ac_trace_printer_default);
}

/** @brief Return current message level
 *  @return current message level
 */
int  ac_trace_get_level(void);

/** @brief Display a message (through means of printer function)
 *  @param[in] 	level for the message
 *  @param[in] 	str   message string
 *  @param[in] 	...   optional arguments
 *  @return none
 */
void  ac_trace(int level, const char * str, ...);


#ifdef __cplusplus
}
#endif

#endif /* __DEBUG_H__ */
